
local alien   = require 'alien'
local alienex = require 'alienex'
local config  = require 'config'


module (...)


local QWORD = alienex.QWORD

local lib = alien.load(config.bass_path)

local function Func(name, types)
  local func = lib["BASS_" .. name]
  func:types(types)
  _M[name] = func
end

VERSION = 0x0204
VERSIONTEXT = "2.4"

OK = 0	-- all is OK
ERROR_MEM = 1	-- memory error
ERROR_FILEOPEN = 2	-- can't open the file
ERROR_DRIVER = 3	-- can't find a free/valid driver
ERROR_BUFLOST = 4	-- the sample buffer was lost
ERROR_HANDLE = 5	-- invalid handle
ERROR_FORMAT = 6	-- unsupported sample format
ERROR_POSITION = 7	-- invalid position
ERROR_INIT = 8	-- BASS_Init has not been successfully called
ERROR_START = 9	-- BASS_Start has not been successfully called
ERROR_ALREADY = 14	-- already initialized/paused/whatever
ERROR_NOCHAN = 18	-- can't get a free channel
ERROR_ILLTYPE = 19	-- an illegal type was specified
ERROR_ILLPARAM = 20	-- an illegal parameter was specified
ERROR_NO3D = 21	-- no 3D support
ERROR_NOEAX = 22	-- no EAX support
ERROR_DEVICE = 23	-- illegal device number
ERROR_NOPLAY = 24	-- not playing
ERROR_FREQ = 25	-- illegal sample rate
ERROR_NOTFILE = 27	-- the stream is not a file stream
ERROR_NOHW = 29	-- no hardware voices available
ERROR_EMPTY = 31	-- the MOD music has no sequence data
ERROR_NONET = 32	-- no internet connection could be opened
ERROR_CREATE = 33	-- couldn't create the file
ERROR_NOFX = 34	-- effects are not available
ERROR_NOTAVAIL = 37	-- requested data is not available
ERROR_DECODE = 38	-- the channel is a "decoding channel"
ERROR_DX = 39	-- a sufficient DirectX version is not installed
ERROR_TIMEOUT = 40	-- connection timedout
ERROR_FILEFORM = 41	-- unsupported file format
ERROR_SPEAKER = 42	-- unavailable speaker
ERROR_VERSION = 43	-- invalid BASS version (used by add-ons)
ERROR_CODEC = 44	-- codec is not available/supported
ERROR_ENDED = 45	-- the channel/file has ended
ERROR_UNKNOWN	= -1	-- some other mystery problem

-- BASS_SetConfig options
CONFIG_BUFFER = 0
CONFIG_UPDATEPERIOD = 1
CONFIG_GVOL_SAMPLE = 4
CONFIG_GVOL_STREAM = 5
CONFIG_GVOL_MUSIC = 6
CONFIG_CURVE_VOL = 7
CONFIG_CURVE_PAN = 8
CONFIG_FLOATDSP = 9
CONFIG_3DALGORITHM = 10
CONFIG_NET_TIMEOUT = 11
CONFIG_NET_BUFFER = 12
CONFIG_PAUSE_NOPLAY = 13
CONFIG_NET_PREBUF = 15
CONFIG_NET_PASSIVE = 18
CONFIG_REC_BUFFER = 19
CONFIG_NET_PLAYLIST = 21
CONFIG_MUSIC_VIRTUAL = 22
CONFIG_VERIFY = 23
CONFIG_UPDATETHREADS = 24
--#if defined(__linux__) || defined (_WIN32_WCE)
CONFIG_DEV_BUFFER = 27
--#endif

-- BASS_SetConfigPtr options
CONFIG_NET_AGENT = 16
CONFIG_NET_PROXY = 17

-- Initialization flags
DEVICE_8BITS = 1	-- use 8 bit resolution, else 16 bit
DEVICE_MONO = 2	-- use mono, else stereo
DEVICE_3D = 4	-- enable 3D functionality
DEVICE_LATENCY = 256	-- calculate device latency (BASS_INFO struct)
DEVICE_CPSPEAKERS = 1024 -- detect speakers via Windows control panel
DEVICE_SPEAKERS = 2048 -- force enabling of speaker assignment
DEVICE_NOSPEAKER = 4096 -- ignore speaker arrangement
--#ifdef __linux__
DEVICE_DMIX = 8192 -- use "dmix" (shared) output
--#endif

-- DirectSound interfaces (for use with BASS_GetDSoundObject)
OBJECT_DS = 1	-- IDirectSound
OBJECT_DS3DL = 2	-- IDirectSound3DListener

DEVICEINFO = alien.defstruct{
  {"name", "string"};
  {"driver", "string"};
  {"flags", "ulong"};
}

DEVICE_ENABLED = 1
DEVICE_DEFAULT = 2
DEVICE_INIT = 4

ATTRIB_FREQ = 1
ATTRIB_VOL = 2
ATTRIB_PAN = 3
ATTRIB_EAXMIX = 4
ATTRIB_MUSIC_AMPLIFY	= 0x100
ATTRIB_MUSIC_PANSEP	= 0x101
ATTRIB_MUSIC_PSCALER	= 0x102
ATTRIB_MUSIC_BPM		= 0x103
ATTRIB_MUSIC_SPEED		= 0x104
ATTRIB_MUSIC_VOL_GLOBAL = 0x105
ATTRIB_MUSIC_VOL_CHAN	= 0x200
ATTRIB_MUSIC_VOL_INST	= 0x300

Func("SetConfig", { ret="int" --[[BOOL]]; "uint" --[[option]], "uint" --[[value]] })
Func("GetConfig", { ret="uint" --[[DWORD]]; "uint" --[[option]] })
Func("SetConfigPtr", { ret="uint" --[[DWORD]]; "pointer" --[[void* value]] })
Func("GetConfigPtr", { ret="pointer" --[[void*]]; "uint" --[[option]] })
Func("GetVersion", { ret="uint" })
Func("ErrorGetCode", { ret="int" })
Func("GetDeviceInfo", { ret="int" --[[BOOL]]; "uint" --[[device]], "pointer" --[[BASS_DEVICEINFO*]] })
Func("Init", { ret="int" --[[BOOL]]; "int" --[[device]], "uint" --[[freq]], "uint" --[[flags]], "pointer" --[[win]], "pointer" --[[dsguid]] })
Func("SetDevice", { ret="int" --[[BOOL]]; "uint" --[[device]] })
Func("GetDevice", { ret="uint" --[[DWORD]];  })
Func("Free", { ret="int" --[[BOOL]];  })
if (alien.platform == 'windows') then
  Func("GetDSoundObject", { ret="pointer"; "uint" --[[object]] })
end
Func("GetInfo", { ret="int" --[[BOOL]]; "pointer" --[[BASS_INFO *info]] })
Func("Update", { ret="int" --[[BOOL]]; "uint" --[[length]] })
Func("GetCPU", { ret="float" })
Func("Start", { ret="int" --[[BOOL]] })
Func("Stop", { ret="int" --[[BOOL]] })
Func("Pause", { ret="int" --[[BOOL]] })
Func("SetVolume", { ret="int" --[[BOOL]]; "float" --[[volume]] })
Func("GetVolume", { ret="float" })
Func("PluginLoad", { ret="uint" --[[HPLUGIN]]; "string" --[[file]], "uint" --[[flags]] })
Func("PluginFree", { ret="int" --[[BOOL]]; "uint" --[[HPLUGIN handle]] })
Func("PluginGetInfo", { ret="pointer" --[[const BASS_PLUGININFO*]]; "uint" --[[HPLUGIN handle]] })
Func("Set3DFactors", { ret="int" --[[BOOL]]; "float" --[[distf]], "float" --[[rollf]], "float" --[[doppf]] })
--Func("Get3DFactors", { ret="int" --[[BOOL]]; "ref float" --[[distf]], "ref float" --[[rollf]], "ref float" --[[doppf]] })
Func("Set3DPosition", { ret="int" --[[BOOL]];
  "pointer" --[[const BASS_3DVECTOR* pos]],
  "pointer" --[[const BASS_3DVECTOR* vel]],
  "pointer" --[[const BASS_3DVECTOR* front]],
  "pointer" --[[const BASS_3DVECTOR* top]] })
Func("Get3DPosition", { ret="int" --[[BOOL]];
  "pointer" --[[BASS_3DVECTOR *pos]],
  "pointer" --[[BASS_3DVECTOR *vel]],
  "pointer" --[[BASS_3DVECTOR *front]],
  "pointer" --[[BASS_3DVECTOR *top]] })
Func("Apply3D", {ret="void"})
if (alien.platform == "windows") then
  Func("SetEAXParameters", { ret="int" --[[BOOL]]; "int" --[[env]], "float" --[[vol]], "float" --[[decay]], "float" --[[damp]] })
  --Func("GetEAXParameters", { ret="int" --[[BOOL]]; "ref uint" --[[env]], "ref float" --[[vol]], "ref float" --[[decay]], "ref float" --[[damp]] })
end
Func("MusicLoad", { ret="uint" --[[HMUSIC]];
  "int" --[[BOOL mem]],
  "pointer" --[[const void* file]],
  QWORD --[[offset]],
  "uint" --[[length]],
  "uint" --[[flags]],
  "uint" --[[freq]] })
Func("MusicFree", { ret="int" --[[BOOL]]; "uint" --[[HMUSIC handle]] })
Func("SampleLoad", { ret="uint" --[[HSAMPLE]];
  "int" --[[BOOL mem]], "pointer" --[[const void* file]], QWORD --[[offset]], "uint" --[[length]], "uint" --[[max]], "uint" --[[flags]] })
Func("SampleCreate", { ret="uint" --[["HSAMPLE]]; "uint" --[[length]], "uint" --[[freq]], "uint" --[[chans]], "uint" --[[max]], "uint" --[[flags]] })
Func("SampleFree", { ret="int" --[[BOOL]]; "uint" --[[HSAMPLE handle]] })
Func("SampleSetData", { ret="int" --[[BOOL]]; "uint" --[[HSAMPLE handle]], "pointer" --[[const void* buffer]] })
Func("SampleGetData", { ret="int" --[[BOOL]]; "uint" --[[HSAMPLE handle]], "pointer" --[[void *buffer]] })
Func("SampleGetInfo", { ret="int" --[[BOOL]]; "uint" --[[HSAMPLE handle]], "pointer" --[[BASS_SAMPLE *info]] })
Func("SampleSetInfo", { ret="int" --[[BOOL]]; "uint" --[[HSAMPLE handle]], "pointer" --[[const BASS_SAMPLE* info]] })
Func("SampleGetChannel", { ret="uint" --[[HCHANNEL]]; "uint" --[[HSAMPLE handle]], "int" --[[BOOL onlynew]] })
Func("SampleGetChannels", { ret="uint" --[[DWORD]]; "uint" --[[HSAMPLE handle]], "pointer" --[[HCHANNEL *channels]] })
Func("SampleStop", { ret="int" --[[BOOL]]; "uint" --[[HSAMPLE handle]] })
Func("StreamCreate", { ret="uint" --[[HSTREAM]];
  "uint" --[[freq]],
  "uint" --[[chans]],
  "uint" --[[flags]],
  "pointer" --[[STREAMPROC *proc]],
  "pointer" --[[void *user]] })
Func("StreamCreateFile", { ret="uint" --[[HSTREAM]];
  "int" --[[BOOL mem]],
  "pointer" --[[const void* file]],
  QWORD --[[offset]],
  QWORD --[[length]],
  "uint" --[[flags]] })
Func("StreamCreateURL", { ret="uint" --[[HSTREAM]];
  "string" --[[url]],
  "uint" --[[offset]],
  "uint" --[[flags]],
  "pointer" --[[DOWNLOADPROC *proc]],
  "pointer" --[[void *user]] })
Func("StreamCreateFileUser", { ret="uint" --[[HSTREAM]];
  "uint" --[[system]],
  "uint" --[[flags]],
  "pointer" --[[const BASS_FILEPROCS* proc]],
  "pointer" --[[void *user]] })
Func("StreamFree", { ret="int" --[[BOOL]]; "uint" --[[HSTREAM handle]] })
Func("StreamGetFilePosition", { ret=QWORD; "uint" --[[HSTREAM handle]], "uint" --[[mode]] })
Func("StreamPutData", { ret="uint" --[[DWORD]]; "uint" --[[HSTREAM handle]], "pointer" --[[const void* buffer]], "uint" --[[length]] })
Func("StreamPutFileData", { ret="uint" --[[DWORD]]; "uint" --[[HSTREAM handle]], "pointer" --[[const void* buffer]], "uint" --[[length]] })
Func("RecordGetDeviceInfo", { ret="int" --[[BOOL]]; "uint" --[[device]], "pointer" --[[BASS_DEVICEINFO *info]] })
Func("RecordInit", { ret="int" --[[BOOL]]; "int" --[[device]] })
Func("RecordSetDevice", { ret="int" --[[BOOL]]; "uint" --[[device]] })
Func("RecordGetDevice", { ret="uint" --[[DWORD]];  })
Func("RecordFree", { ret="int" --[[BOOL]];  })
Func("RecordGetInfo", { ret="int" --[[BOOL]]; "pointer" --[[BASS_RECORDINFO *info]] })
Func("RecordGetInputName", { ret="string"; "int" --[[input]] })
Func("RecordSetInput", { ret="int" --[[BOOL]]; "int" --[[input]], "uint" --[[flags]], "float" --[[volume]] })
--Func("RecordGetInput", { ret="uint" --[[DWORD]]; "int" --[[input]], "ref float" --[[volume]] })
Func("RecordStart", { ret="uint" --[[HRECORD]];
  "uint" --[[freq]],
  "uint" --[[chans]],
  "uint" --[[flags]],
  "pointer" --[[RECORDPROC *proc]], 
  "pointer" --[[void *user]] })
Func("ChannelBytes2Seconds", { ret="double"; "uint" --[[handle]], QWORD --[[pos]] })
Func("ChannelSeconds2Bytes", { ret=QWORD; "uint" --[[handle]], "double" --[[pos]] })
Func("ChannelGetDevice", { ret="uint" --[[DWORD]]; "uint" --[[handle]] })
Func("ChannelSetDevice", { ret="int" --[[BOOL]]; "uint" --[[handle]], "uint" --[[device]] })
Func("ChannelIsActive", { ret="uint" --[[DWORD]]; "uint" --[[handle]] })
Func("ChannelGetInfo", { ret="int" --[[BOOL]]; "uint" --[[handle]], "pointer" --[[BASS_CHANNELINFO *info]] })
Func("ChannelGetTags", { ret="string"; "uint" --[[handle]], "uint" --[[tags]] })
Func("ChannelFlags", { ret="uint" --[[DWORD]]; "uint" --[[handle]], "uint" --[[flags]], "uint" --[[mask]] })
Func("ChannelUpdate", { ret="int" --[[BOOL]]; "uint" --[[handle]], "uint" --[[length]] })
Func("ChannelLock", { ret="int" --[[BOOL]]; "uint" --[[handle]], "int" --[[BOOL lock]] })
Func("ChannelPlay", { ret="int" --[[BOOL]]; "uint" --[[handle]], "int" --[[BOOL restart]] })
Func("ChannelStop", { ret="int" --[[BOOL]]; "uint" --[[handle]] })
Func("ChannelPause", { ret="int" --[[BOOL]]; "uint" --[[handle]] })
Func("ChannelSetAttribute", { ret="int" --[[BOOL]]; "uint" --[[handle]], "uint" --[[attrib]], "float" --[[value]] })
--Func("ChannelGetAttribute", { ret="int" --[[BOOL]]; "uint" --[[handle]], "uint" --[[attrib]], "ref float" --[[value]] })
Func("ChannelSlideAttribute", { ret="int" --[[BOOL]]; "uint" --[[handle]], "uint" --[[attrib]], "float" --[[value]], "uint" --[[time]] })
Func("ChannelIsSliding", { ret="int" --[[BOOL]]; "uint" --[[handle]], "uint" --[[attrib]] })
Func("ChannelSet3DAttributes", { ret="int" --[[BOOL]]; "uint" --[[handle]], "int" --[[mode]], "float" --[[min]], "float" --[[max]], "int" --[[iangle]], "int" --[[oangle]], "float" --[[outvol]] })
--[=[
Func("ChannelGet3DAttributes", { ret="int" --[[BOOL]];
  "uint" --[[handle]],
  "ref uint" --[[mode]],
  "ref float" --[[min]],
  "ref float" --[[max]],
  "ref uint" --[[iangle]],
  "ref uint" --[[oangle]],
  "ref float" --[[outvol]] })
  --]=]
Func("ChannelSet3DPosition", { ret="int" --[[BOOL]];
  "uint" --[[handle]],
  "pointer" --[[const BASS_3DVECTOR* pos]],
  "pointer" --[[const BASS_3DVECTOR* orient]],
  "pointer" --[[const BASS_3DVECTOR* vel]] })
Func("ChannelGet3DPosition", { ret="int" --[[BOOL]];
  "uint" --[[handle]],
  "pointer" --[[BASS_3DVECTOR *pos]],
  "pointer" --[[BASS_3DVECTOR *orient]],
  "pointer" --[[BASS_3DVECTOR *vel]] })
Func("ChannelGetLength", { ret=QWORD; "uint" --[[handle]], "uint" --[[mode]] })
Func("ChannelSetPosition", { ret="int" --[[BOOL]]; "uint" --[[handle]], QWORD --[[pos]], "uint" --[[mode]] })
Func("ChannelGetPosition", { ret=QWORD; "uint" --[[handle]], "uint" --[[mode]] })
Func("ChannelGetLevel", { ret="uint" --[[DWORD]]; "uint" --[[handle]] })
Func("ChannelGetData", { ret="uint" --[[DWORD]]; "uint" --[[handle]], "pointer" --[[void *buffer]], "uint" --[[length]] })
Func("ChannelSetSync", { ret="uint" --[[HSYNC]];
  "uint" --[[handle]],
  "uint" --[[type]],
  QWORD --[[param]],
  "pointer" --[[SYNCPROC *proc]],
  "pointer" --[[void *user]] })
Func("ChannelRemoveSync", { ret="int" --[[BOOL]]; "uint" --[[handle]], "uint" --[[HSYNC sync]] })
Func("ChannelSetDSP", { ret="uint" --[[HDSP]]; "uint" --[[handle]], "pointer" --[[DSPPROC *proc]], "pointer" --[[void *user]], "int" --[[priority]] })
Func("ChannelRemoveDSP", { ret="int" --[[BOOL]]; "uint" --[[handle]], "uint" --[[HDSP dsp]] })
Func("ChannelSetLink", { ret="int" --[[BOOL]]; "uint" --[[handle]], "uint" --[[chan]] })
Func("ChannelRemoveLink", { ret="int" --[[BOOL]]; "uint" --[[handle]], "uint" --[[chan]] })
Func("ChannelSetFX", { ret="uint" --[[HFX]]; "uint" --[[handle]], "uint" --[[type]], "int" --[[priority]] })
Func("ChannelRemoveFX", { ret="int" --[[BOOL]]; "uint" --[[handle]], "uint" --[[HFX fx]] })
Func("FXSetParameters", { ret="int" --[[BOOL]]; "uint" --[[HFX handle]], "pointer" --[[const void* params]] })
Func("FXGetParameters", { ret="int" --[[BOOL]]; "uint" --[[HFX handle]], "pointer" --[[void *params]] })
Func("FXReset", { ret="int" --[[BOOL]]; "uint" --[[HFX handle]] })
